文档

会话接口集成概述

更新时间:

通过SSE流式调用TongyiBeebotChat。

集成步骤

有关集成时序图与步骤描述如下

1a1f40dd5b321dbeb13ae99ae9ded3bf

  1. 依据SSE连接协议,获取SSE访问路径URL,参考文档:SSE流式接口;

  2. 通过SSE流式调用TongyiBeebotChat,并通过监听SSE,获取TongyiBeebotChat的流式响应。

重要
  • 获取SSE访问路径URL示例代码:

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

import org.apache.commons.codec.binary.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Test {
    private static char[] toDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static void main(String[] args) throws Exception {
        //aliyun账号AK、SK,登录阿里云账号获取
        String accessAK = "<你的AK>";
        String accessSK = "<你的SK>";

        //业务空间AgentKey,获取地址:https://alime.console.aliyun.com/?productCode=p_ics#/business_management/business_management
        String agentKey = "<你的AgentKey>";
        //机器人实例id,在控制台进入机器人查看
        String instanceId = "<你的机器人实例id>";
        String question = "<你好>";

        ConnectInfo connectInfo = getConnectInfo(accessAK,accessSK,agentKey);
        String sseUrl = getSseUrl(connectInfo);

        //SSEListener最佳实践,是有前端js实现,我们把sseUrl信息给前端,前端通过js直连SSE,避免从后端中转SSE,降低不必要的网络开销
        //前端连sse的库也比较容易,前端直接请求SSE接口,几行代码就够了
        new SSEListener(sseUrl,question,instanceId).executeSSE();
    }

    private static ConnectInfo getConnectInfo(String accessAk,String accessSK,String agentKey) throws ClientException {
        String popRegion = "cn-shanghai";
        String popProduct = "Chatbot";
        String popDomain = "chatbot.cn-shanghai.aliyuncs.com";
        DefaultProfile.addEndpoint(popRegion, popProduct, popDomain);
        IClientProfile profile = DefaultProfile.getProfile(popRegion, accessAk, accessSK);
        profile.getHttpClientConfig().setProtocolType(ProtocolType.HTTPS);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        //固定入参
        //
        CommonRequest commonRequest = new CommonRequest();
        commonRequest.setSysProduct("Chatbot");
        commonRequest.setSysMethod(MethodType.GET);
        //根据API会有变化
        commonRequest.setSysAction("ApplyForStreamAccessToken");
        commonRequest.setSysVersion("2022-04-08");
        commonRequest.putQueryParameter("AgentKey",agentKey);
        CommonResponse commonResponse = client.getCommonResponse(commonRequest);
        return JSONObject.parseObject(commonResponse.getData(), ConnectInfo.class);
    }

    /**
     * /sse/paas4Json/{accessToken}/{channelId}/{sign}/{timestamp}
     */
    private static String getSseUrl(ConnectInfo connectInfo) throws NoSuchAlgorithmException {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String sign = getSigin(connectInfo.getStreamSecret(),timestamp);
        return String.format("https://alime-ws.aliyuncs.com/sse/paas4Json/%s/%s/%s/%s",connectInfo.getAccessToken(),connectInfo.getChannelId(),sign,timestamp);
    }

    private static String getSigin(String streamSecret, String timestamp) throws NoSuchAlgorithmException {
        StringBuilder sb = new StringBuilder();
        sb.append("streamSecret=").append(streamSecret)
                .append("&timestamp=").append(timestamp);

        byte[] md5Str= md5(sb.toString());
        return encodeHex(md5Str,toDigits);
    }

    private static byte[] md5(String text) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] md5Bytes = md.digest(StringUtils.getBytesUtf8(text));
        return md5Bytes;
    }


    public static String encodeHex(byte[] data, char[] toDigits) {
        int l = data.length;
        char[] out = new char[l << 1];
        int i = 0;

        for(int var5 = 0; i < l; ++i) {
            out[var5++] = toDigits[(240 & data[i]) >>> 4];
            out[var5++] = toDigits[15 & data[i]];
        }
        return new String(out);
    }

    private static class ConnectInfo {
        private String accessToken;
        private String streamSecret;
        private String channelId;

        public String getAccessToken() {
            return accessToken;
        }

        public void setAccessToken(String accessToken) {
            this.accessToken = accessToken;
        }

        public String getStreamSecret() {
            return streamSecret;
        }

        public void setStreamSecret(String streamSecret) {
            this.streamSecret = streamSecret;
        }

        public String getChannelId() {
            return channelId;
        }

        public void setChannelId(String channelId) {
            this.channelId = channelId;
        }
    }
}
  • 以下示例代码包含连接SSE监听SSE。该段代码仅为调用Tongyibeebotchat接口示例Demo,实际上线可根据业务需求修改。

import com.alibaba.fastjson.JSON;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.sse.EventSources;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;

import java.net.Proxy;
import java.util.concurrent.TimeUnit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;


public class SSEListener extends EventSourceListener {
    private static OkHttpClient okHttpClient;
    private static ConnectionPool connectionPool = new ConnectionPool(10, 5, TimeUnit.MINUTES);

    private String sseUrl;
    private String text;
    private String instanceId;


    public SSEListener(String sseUrl,String text,String instanceId) {
        this.sseUrl = sseUrl;
        this.text = text;
        this.instanceId = instanceId;
    }

    public void executeSSE() throws Exception {
        RequestBody formBody = RequestBody.create(getMessage(), MediaType.parse("application/json; charset=utf-8"));
        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.url(getSseUrl()).post(formBody).build();
        EventSource.Factory factory = EventSources.createFactory(getInstance());
        //创建事件
        factory.newEventSource(request, this);
    }

    public static OkHttpClient getInstance() {
        if (okHttpClient == null) { //加同步安全
            synchronized (OkHttpClient.class) {
                if (okHttpClient == null) { //okhttp可以缓存数据....指定缓存路径
                    okHttpClient = new OkHttpClient.Builder()//构建器
                            .proxy(Proxy.NO_PROXY) //来屏蔽系统代理
                            .connectionPool(connectionPool)
                            .connectTimeout(600, TimeUnit.SECONDS)//连接超时
                            .writeTimeout(600, TimeUnit.SECONDS)//写入超时
                            .readTimeout(600, TimeUnit.SECONDS)//读取超时
                            .build();
                    okHttpClient.dispatcher().setMaxRequestsPerHost(200);
                    okHttpClient.dispatcher().setMaxRequests(200);
                }
            }
        }
        return okHttpClient;
    }

    /**
     * {@inheritDoc}
     * 建立sse连接
     */
    @Override
    public void onOpen(final EventSource eventSource, final Response
            response) {
        System.out.println("建立sse连接...");
    }

    /**
     * 事件
     *
     * @param eventSource
     * @param id
     * @param type
     * @param data
     */
    @Override
    public void onEvent(EventSource eventSource, String id, String type, String data) {
        try {
            System.out.println("流式返回结果:"+data);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onClosed(final EventSource eventSource) {
        System.out.println("sse连接关闭...");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onFailure(final EventSource eventSource, final Throwable t, final Response response) {
        System.out.println("onFailure...");
    }

    //    {
//        "messageId": "shdlfjldjfldf",
//            "action":"TongyiBeebotChat",
//            "version":"2022-04-08",
//            "data": [
//        {
//            "type": "JSON_TEXT",
//                "value": "{"InstanceId":"xxx","Utterance":"你好"}"
//        }
//        ]
//    }
//     */
    private String getMessage() {
        MessageInfo messageInfo = new MessageInfo();
        messageInfo.setMessageId(UUID.randomUUID().toString());
        messageInfo.setAction("TongyiBeebotChat");
        messageInfo.setVersion("2022-04-08");
        List<HashMap> data = new ArrayList<HashMap>();
        HashMap<String,String> param = new HashMap<String,String>();
        param.put("type","JSON_TEXT");
        param.put("value", JSON.toJSONString(new HashMap<String,String>(){
            {
                put("InstanceId",getInstanceId());
                put("Utterance",getText());
            }
        }));
        data.add(param);
        messageInfo.setData(data);
        return JSON.toJSONString(messageInfo);
    }

    public String getSseUrl() {
        return sseUrl;
    }

    public void setSseUrl(String sseUrl) {
        this.sseUrl = sseUrl;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getInstanceId() {
        return instanceId;
    }

    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }

    private static class MessageInfo {
        private String messageId;
        private String action;
        private String version;
        private List<HashMap> data;

        public String getMessageId() {
            return messageId;
        }

        public void setMessageId(String messageId) {
            this.messageId = messageId;
        }

        public String getAction() {
            return action;
        }

        public void setAction(String action) {
            this.action = action;
        }

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public List<HashMap> getData() {
            return data;
        }

        public void setData(List<HashMap> data) {
            this.data = data;
        }
    }

}

其他

接口调用建议:由后端生成SSE请求连接所需要的accessToken、channelId、sign、timestamp参数给前端。前端通过js连接SSE,进行流式交互。

  • 本页导读 (0)